package com.xuecheng.media.java8;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * 11.4 对多个任务进行流水线操作
 */
public class Discount {


    /**
     * 将折扣代码应用于商品最初的原始价格
     *
     * @param quote
     * @return
     */
    public static String applyDiscount(Quote quote) {
        return quote.getShopName() + " price is " + Discount.applyDiscount(quote);
    }

    /**
     * 模拟Discount服务响
     *
     * @param price
     * @param code
     * @return
     */
    public static double apply(double price, Code code) {
        //delay();
        return price * (100 - code.percentage) / 100;
    }

    /**
     * 11.4.2 获取价格
     *
     * @param product
     * @return
     */
    public List<String> findPrices(String product) {
        List<shop> shops = new ArrayList<>();
        return shops.stream()
                .map(shop -> shop.getPrice(product))//取得每个shop对象中商品的原始价
                .map(Quote::parse)//在Quote对象中对shop返回的字符串进行转换
                .map(Discount::applyDiscount)//联系Discount服务，为每个Quote申请折扣
                .collect(Collectors.toList());
    }


    /**
     * 11.4.3 构造同步和异步操作
     *
     * @param product
     * @return
     */
    public List<String> findSyncPrices(String product) {
        List<shop> shops = new ArrayList<>();
        Executor executor = new Executor() {
            @Override
            public void execute(@NotNull Runnable command) {

            }
        };
        return shops.stream()
                //以异步方式取得每个shop中指定产品的原始价格
                .map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product), executor))
                //Quote对象存在时，对其返回的值进行转换
                .map(future -> future.thenApply(Quote::parse))
                //是哟哦那个另一个一步任务构造期望Future，申请折扣
                .map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() ->
                        Discount.applyDiscount(quote), executor)))
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
    }


    /**
     * 11.4.4 两个对象整合起来
     *
     * @param product
     * @return
     */
    public List<Double> findSyncFuturePrices(String product) throws ExecutionException, InterruptedException {
        List<Double> priceList = new ArrayList<>();
        CompletableFuture<Double> futurePriceInUSD = CompletableFuture.supplyAsync(() -> shop.getPrice(product))
                //创建第一个任务取得商品的价格
                .thenCombine(CompletableFuture.supplyAsync(() ->
                                //创建第二个任务，查询美元和欧元之间的转换汇率
                                getRate(Money.EUR, Money.USD)),
                        //通过乘法整合得到的商品价格和汇率
                        (price, rate) -> Double.valueOf(price) * Double.valueOf(rate));
        Double v = futurePriceInUSD.get();
        priceList.add(v);
        return priceList;
    }


    private String getRate(Money money, Money money1) {
        return "";
    }

    /**
     * 折扣价格枚举类
     */
    public enum Code {
        NONE(0),
        SILVER(5),
        GOLD(10),
        PLATINUM(15),
        DIAMOND(20);

        private final int percentage;

        Code(int percentage) {
            this.percentage = percentage;
        }
    }

    /**
     * 汇率
     */
    public enum Money {
        EUR,
        USD
    }
}


class Quote {
    private final String shopName;

    private final double price;


    private final Discount.Code discountCode;

    public Quote(String shopName, double price, Discount.Code discountCode) {
        this.shopName = shopName;
        this.price = price;
        this.discountCode = discountCode;
    }

    /**
     * 解析返回的价格字符串
     *
     * @param s。价格字符串
     * @return 返回Quote对象
     */
    public static Quote parse(String s) {
        String[] split = s.split(":");
        String shopName = split[0];
        double price = Double.parseDouble(split[1]);
        Discount.Code discountCode = Discount.Code.valueOf(split[2]);
        return new Quote(shopName, price, discountCode);
    }

    public String getShopName() {
        return shopName;
    }

    public double getPrice() {
        return price;
    }

    public Discount.Code getDiscountCode() {
        return discountCode;
    }


}


/**
 * 商品实体类
 */
class shop {

    private double price;

    public static String getPrice(String product) {
        double price = calculatePrice(product);
        Random random = new Random();
        Discount.Code value = Discount.Code.values()[random.nextInt(Discount.Code.values().length)];
        return String.format("%s:%.2f:%s", product, price, value);
    }


    public void setPrice(double price) {
        this.price = price;
    }

    private static double calculatePrice(String product) {
        //delay();
        Random random = new Random();
        return random.nextDouble() * product.charAt(0) + product.charAt(1);
    }
}





